<?php
require_once PATH_SITE.'cn/royan/php/utils/builders/BuilderUser.builder.php';
require_once PATH_SITE.'cn/royan/php/utils/builders/BuilderSocket.builder.php';
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
require_once PATH_SITE.'org/puremvc/php/patterns/proxy/Proxy.php';
/**
 * Description of SocketProxy
 *
 * @author Royan
 */
class SocketProxy extends Proxy
{
    const NAME = "SocketProxy";
    
    protected $socket;
    
    //put your code here
    public function __construct() {
        parent::__construct( SocketProxy::NAME );
        
        IF( !function_exists('socket_create') )
        {
            Logger::trace( 'Your PHP socket extension is not configured properly' );
            throw new Exception( 'Your PHP socket extension is not configured properly' );
            EXIT;
        }
    }
    
    public function runServer( $config )
    {
        IF( ( $socket = socket_create( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
            Logger::trace( "socket_create() error msg:".socket_strerror( $socket ) );
        ELSE
            Logger::trace( $socket." socket create" );

        IF ( socket_set_option( $socket, SOL_SOCKET, SO_REUSEADDR, 1 ) < 0 )
            Logger::trace( "socket_set_option() error msg:".socket_strerror( socket_last_error() ) );
        ELSE
            Logger::trace( "socket set option" );

        IF ( socket_set_nonblock( $socket ) < 0 )
            Logger::trace( "socket_set_nonblock() error msg:".socket_strerror( socket_last_error() ) );
        ELSE
            Logger::trace( "socket set nonblock" );
        
        IF( ( $ret = socket_bind( $socket, (string)$config->__get( "host" ), (int)$config->__get( "port" ) ) ) < 0 )
            Logger::trace( "socket_bind() error msg:".socket_strerror( $ret ) );
        ELSE
            Logger::trace( "bind ". $config->__get( "host" ).":".$config->__get( "port" ) );

        IF( ( $ret = socket_listen( $socket, 6 ) ) < 0 )
            Logger::trace( "socket_listen() error msg:".socket_strerror( $ret ) );
        ELSE
            Logger::trace( "start listen..." );
        
        $value = array( "socket"=> &$socket,
                        "config"=> $config );
        $builderSocket = new BuilderSocket( $value );
        $server = $builderSocket->build()->getResult();
        
        $connectProxy = ConnectParse::getInstance();
        
        $this->setData( $server );
        $connects = & $server->__get( "connects" );
        
        DO {
            $readFDs = array();
            array_push( $readFDs, $socket );
            
            FOR( $i = 0; $i < count( $connects ); $i++ )
                IF( isset( $connects[$i] ) )
                    array_push( $readFDs, $connects[$i] );

            IF ( count( $readFDs ) > 0 )
                $ready = @socket_select( $readFDs, $w, $e, NULL );
            
            IF( in_array( $socket, $readFDs ) )
            {
                FOR( $i = 0 ; $i <= count( $connects ); $i++ )
                {
                    IF( !isset( $connects[$i] ) || $connects[$i] == NULL )
                    {
                        $connects[$i] = @socket_accept( $socket );
                        IF( $connects[$i] ){
                            socket_setopt( $connects[$i], SOL_SOCKET, SO_REUSEADDR, 1 );
                            socket_getpeername( $connects[$i], $peer_host, $peer_port );
                            
                            Logger::trace( "New connection ( ".($i + 1)." ) from ".$peer_host." on port ".$peer_port );
							
                            $userInfo = array( 'serverId'=>$i,
                                               'screenname'=> 'guest'.$i,
                                               'socket'=>$connects[$i],
                                               'host'=> $peer_host);
                            $builderUser = new BuilderUser( $userInfo );
                            $user = $builderUser->build()->getResult();
                            
                            $this->sendNotification( ApplicationFacade::USER_START_CONNECT, $builderUser->getResult() );
                            BREAK;
                        }
                    }
                }
                
                IF( --$ready <= 0 )
                    CONTINUE;
            }
            
            FOR( $i = 0; $i < count( $connects ); $i++ )
            {
                IF( !isset( $connects[$i] ) )
                    CONTINUE;

                IF( in_array( $connects[$i], $readFDs ) )
                {	
                    $data = "";
                    WHILE( $buf = @socket_read( $connects[$i], 1024, PHP_BINARY_READ ) )
                    {
                        $data .= $buf;
                        $endString = substr( $buf, - strlen( "\n" ) );
                        IF( $endString == "\n" )
                            BREAK;
                    }

                    //	empty data => connection was closed
                    IF( !$data )
                    {
                        $this->sendNotification( ApplicationFacade::USER_END_CONNECT, $connects[$i] );
                    }
                    ELSE
                    {
                        $receive = array( 'client'=>$connects[$i],
                                          'message'=>$data );
                        $this->sendNotification( ApplicationFacade::RECEIVE_CLIENT_DATA, $receive );
                    }
                }
            }
        } WHILE ( TRUE );
    }
}

?>
